﻿using Microsoft.Win32;
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ToolGen
{
    public class MySql
    {
        public static string ReturnAllTable(string table_schema)
        {
            string strFormat = @"SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA='{0}'";
            return String.Format(strFormat, table_schema);
        }

        public static string ReturnAllView()
        {
            return "SHOW VIEWS";
        }
        public static string ReturnAllTable()
        {
            return "SHOW TABLES";
        }

        public static string Describe(string table_name)
        {
            return "DESCRIBE " + table_name;
        }
    }
    public class SqlServer
    {
        public static string ReturnAllView()
        {
            return @"SELECT name as TABLE_NAME FROM sys.views";
            
        }
        public static string ReturnAllTable(string table_catalog)
        {
            string strFormat = @"SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_CATALOG='{0}'";
            return String.Format(strFormat, table_catalog);
        }

        public static string Describle(string table_name)
        {
            string strFormat = @"SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '{0}'";
            return String.Format(strFormat, table_name);
        }
        public static string ReturnTables()
        {
            return "SHOW TABLES";
        }

    }

    public class GenCode
    {
        public MySqlConnection _connMySql {get;set;}
        public SqlConnection _connSqlServer { get; set; }
        public string _folderSave { get; set; }
        public bool _isProtobuff { get; set; }

        /// <summary>
        /// 1: MySql, 2: SqlServer
        /// </summary>
        public int _typeConn { get; set; }
        public GenCode(int typeConn, string folderSave, SqlConnection connSqlServer = null, MySqlConnection connMySql = null, bool isProtobuf=false)
        {
            _typeConn = typeConn;
            _folderSave = folderSave;
            _connSqlServer = connSqlServer;
            _connMySql = connMySql;
            _isProtobuff = isProtobuf;
        }
        public void Generate(string[] cmdSegments)
        {
            string currentCmd = cmdSegments[0];
            cmdSegments = cmdSegments.Where(x => x != currentCmd && x != "").ToArray();

            switch (currentCmd)
            {
                case "entity":
                    Entity(cmdSegments);
                    break;
                default:
                    WriteError(currentCmd + " is not a supported command.");
                    break;
            }
        }

        public void Entity(string[] cmdSegments)
        {
            if (cmdSegments.Length == 3)
            {
                string entityName = cmdSegments[0];
                string tableName = cmdSegments[1];
                string programmingLanguage = cmdSegments[2];
                string strDes = string.Empty;
                StringBuilder entityClass = new StringBuilder();
                string fileExtension = "";

                /// MySQL
                if (_typeConn == 1)
                {
                    strDes = MySql.Describe(tableName);
                    if (_connMySql != null)
                    {
                        using (MySqlCommand mysqlCmd = new MySqlCommand(strDes, _connMySql))
                        {
                            try
                            {
                                MySqlDataReader reader = mysqlCmd.ExecuteReader();

                                List<string> fields = new List<string>();
                                List<string> fieldDataTypes = new List<string>();

                                while (reader.Read())
                                {
                                    fields.Add(reader[0].ToString());
                                    string dType = reader[1].ToString();

                                    int chPos = dType.IndexOf('(');
                                    if (chPos > -1)
                                    {
                                        dType = dType.Substring(0, chPos);
                                    }

                                    fieldDataTypes.Add(dType);
                                }
                                reader.Close();                               
                               

                                SaveFile(entityClass, fileExtension, entityName, programmingLanguage, fields, fieldDataTypes);
                                
                            }
                            catch (Exception e)
                            {
                                OpenMessageBox(e.Message);
                            }
                        }
                    }
                    else
                    {
                        OpenMessageBox("MySql connection is not open. Type help for usage.");
                    }
                }
                /// Sql Server
                else
                {
                    strDes = SqlServer.Describle(tableName);
                    if (_connSqlServer != null)
                    {
                        using (SqlCommand sqlCmd = new SqlCommand(strDes, _connSqlServer))
                        {
                            try
                            {
                                SqlDataReader reader = sqlCmd.ExecuteReader();

                                List<string> fields = new List<string>();
                                List<string> fieldDataTypes = new List<string>();

                                while (reader.Read())
                                {
                                    fields.Add(reader[0].ToString());
                                    string dType = reader[1].ToString();

                                    int chPos = dType.IndexOf('(');
                                    if (chPos > -1)
                                    {
                                        dType = dType.Substring(0, chPos);
                                    }

                                    fieldDataTypes.Add(dType);
                                }
                                reader.Close();


                                

                                SaveFile(entityClass, fileExtension, entityName, programmingLanguage, fields, fieldDataTypes);

                            }
                            catch (Exception e)
                            {
                                OpenMessageBox(e.Message);
                            }
                        }
                    }
                    else
                    {
                        OpenMessageBox("MySql connection is not open. Type help for usage.");
                    }
                }
            }
            else
            {
                OpenMessageBox("Incorrect number of arguments. Type help for usage");
            }
            
        }

        private void OpenMessageBox(string message)
        {
            MessageBox.Show(message, "Gen Code", MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
        }

        private void SaveFile(StringBuilder entityClass, string fileExtension, string entityName, string programmingLanguage, List<string> fields, List<string> fieldDataTypes)
        {
            switch (programmingLanguage)
            {
                case "cs":
                    if (_isProtobuff)
                    {
                        //[ProtoContract]
                        entityClass.AppendLine("using ProtoBuf;");
                    }
                    entityClass.AppendLine("using System;");
                    entityClass.AppendLine();
                    if (_isProtobuff)
                    {
                        entityClass.AppendLine("[ProtoContract]");
                    }
                    entityClass.AppendLine("public class " + entityName);
                    entityClass.AppendLine("{");

                    int idx = 0;
                    foreach (string field in fields)
                    {
                        string dType = "";

                        switch (fieldDataTypes[idx])
                        {
                            case "int":
                            case "smallint":
                            case "tinyint":
                                dType = "int";
                                break;
                            case "bigint":
                                dType = "long";
                                break;
                            case "double":
                                dType = "double";
                                break;
                            case "decimal":                            
                                dType = "decimal";
                                break;
                            case "float":
                                dType = "float";
                                break;
                            case "nvarchar":
                            case "ntext":
                            case "varchar":
                            case "text":
                            case "char":
                                dType = "string";
                                break;
                            case "timestamp":
                            case "datetime":
                                dType = "DateTime";
                                break;
                            case "bit":
                            case "bool":
                                dType = "bool";
                                break;
                            default:
                                dType = "object";
                                break;

                        }
                        entityClass.AppendLine();
                        if (_isProtobuff)
                        {
                            //[ProtoMember(1)]
                            entityClass.AppendLine("\t[ProtoMember(" + (idx + 1) + ")]");
                        }
                        entityClass.Append("\tpublic " + dType + " " + field);
                        entityClass.Append(" { get; set; }");
                        //entityClass.Append("set;");
                        //entityClass.Append("\t\tget;");
                        //entityClass.Append("\t}");
                        ++idx;
                    }
                    entityClass.AppendLine("");
                    entityClass.AppendLine("}");
                    fileExtension = "cs";
                    break;
            }
            if (fileExtension != "")
            {
                try
                {
                    string path = _folderSave; //GetRegValue("path");
                    string fileName = "";

                    if (path != "")
                    {
                        fileName = path + "\\" + entityName + "." + fileExtension;
                    }
                    else
                    {
                        fileName = entityName + "." + fileExtension;
                    }

                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }

                    using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
                    {
                        StreamWriter sWriter = new StreamWriter(fs);
                        sWriter.Write(entityClass);
                        sWriter.Flush();
                        sWriter.Close();

                        //OpenMessageBox("Entity " + entityName + " generated: " + fileName);
                    }
                }
                catch (Exception ioe)
                {
                    OpenMessageBox(ioe.Message);
                    //WriteError(ioe.Message);
                }
            }
            else
            {
                OpenMessageBox("Entity type " + programmingLanguage + " is not supported");
            }
        }

        private void WriteMessage(string message)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine(message);
            Console.ForegroundColor = ConsoleColor.Gray;
        }

        private void WriteError(string message)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(message);
            Console.ForegroundColor = ConsoleColor.Gray;
        }
        private string GetRegValue(string key)
        {
            RegistryKey softwareKey = Registry.CurrentUser.OpenSubKey("Software", true);
            RegistryKey appKey = softwareKey.OpenSubKey("MySqlQueryTool", true);

            if (appKey != null)
            {
                return appKey.GetValue(key).ToString();
            }
            return "";
        }

        private string[] ParseCommand(string cmd)
        {
            string[] segments = cmd.Split(new char[] { ' ' });
            return segments;
        }
    }
}
